#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "PopupItem.h"

#include "Class.h"
#include "Menu.h"
#include "SeqColl.h"
#include "Look.h"
#include "MenuBar.h"
#include "TextItem.h"
#include "WindowSystem.h"
#include "Clipper.h"
#include "Filler.h"

const int cPullRight= 16;

//---- MenuButton --------------------------------------------------------------

NewMetaImpl(MenuButton,StateButton, (TP(menu)));

MenuButton::MenuButton(int id, Menu *m, VObject *l) : StateButton(id, l)
{
	menu= m;
	state= cIdNone;
	SetFlag(eVObjVFixed|eVObjHFixed);
}

MenuButton::~MenuButton()
{
	SafeDelete(menu);
}

Menu *MenuButton::MyMenu()
{
	return menu;
}

OStream& MenuButton::PrintOn(OStream &s)
{
	StateButton::PrintOn(s);
	return s << menu SP;
}

IStream& MenuButton::ReadFrom(IStream &s)
{
	StateButton::ReadFrom(s);
	return s >> menu;
}

void MenuButton::CollectParts(Collection* col)
{
	StateButton::CollectParts(col);
	if (menu)
		col->Add(menu);
}

void MenuButton::SetCollection(SeqCollection *col, bool freeold)
{
	if (menu)
		menu->SetCollection(col, freeold);
}

//---- PopupButton -------------------------------------------------------------

NewMetaImpl0(PopupButton,MenuButton);

PopupButton::PopupButton(int id, int dfltid, Menu *m) : MenuButton(id, m)
{
	SetValue(dfltid, FALSE);
	ResetFlag(eVObjHFixed);
}

void PopupButton::SetContainer(VObject *v)
{
	MenuButton::SetContainer(v);
	menu->SetNextHandler(this);
}

void PopupButton::Control(int id, int part, void *v)
{
	if (id == cIdNone)
		return;
	if (part == cPartViewSize || part == cPartAnyChange)
		return;
	MenuButton::Control(id, part, v);
}

Command *PopupButton::DispatchEvents(Point lp, Token &t, Clipper *vf)
{
	if (t.Code == eEvtLeftButton && !(t.Flags & eFlgButDown)) {
		Command *currCmd= DoLeftButtonDownCommand(lp, t, WindowSystem::Clicks);
		if (currCmd && currCmd != gNoChanges && vf)
			currCmd= vf->TrackInContent(lp, t, currCmd);
		return currCmd;
	}
	return MenuButton::DispatchEvents(lp, t, vf);
}

Metric PopupButton::GetMinSize()
{
	if (menu) {
		Metric m;
		Iter next(menu->GetCollection());
		register VObject *vop;

		while (vop= (VObject*) next())
			m.Merge(vop->GetMinSize());
		
		return m.Expand(2);
	}
	return MenuButton::GetMinSize();
}

void PopupButton::DoTrackMouse(TrackPhase atp, Point)
{
	if (Enabled() && atp == eTrackPress && menu) {
		int id= menu->Popup(GetOrigin()+Point(0,-1), this, state, TRUE, TRUE, gRect0);
		if (id != cIdNone) {
			SetValue(id);
			Control(GetId(), cPartToggle, (void*)id);
		}
	}
}

void PopupButton::Draw(Rectangle r)
{
	VObject *v= menu->FindItem(state);
	if (v == 0)
		v= (VObject*)menu->GetCollection()->At(0);
	if (v) {
		int oldstate;
		StateButton *stb= 0;
		if (v->IsKindOf(StateButton))
			stb= (StateButton*) v;
		if (stb) {
			oldstate= stb->GetValue();
			stb->SetValue(0, FALSE);
		}
		state= v->GetId();
		Point old(v->GetOrigin());
		bool isopen= v->IsOpen();
		if (!isopen)
			v->Open();
		v->SetOrigin(GetOrigin()+gPoint2);
		v->SetExtent(GetExtent()-gPoint4);
		v->DrawAll(r);
		gLook->PopupButtonLayout()->Adorn(this, r, Enabled() ? 0 : 2);
		v->SetOrigin(old);
		if (!isopen)
			v->Close();
		if (stb)
			stb->SetValue(oldstate, FALSE);
	}
}

//---- PullDownButton ----------------------------------------------------------

NewMetaImpl0(PullDownButton,MenuButton);

PullDownButton::PullDownButton(Menu *m, VObject *l) : MenuButton(cIdNone, m, l)
{
	if (m && l == 0)
		Add(new TextItem(m->GetName(), gSysFont, Point(8,2)));
}

PullDownButton::PullDownButton(int id, Menu *m, VObject *l) : MenuButton(id, m, l)
{
	if (m && l == 0)
		Add(new TextItem(m->GetName(), gSysFont, Point(8,2)));
}

extern bool gInButtonFlush;

void PullDownButton::DoTrackMouse(TrackPhase atp, Point)
{
	if (Enabled()) {
		switch (atp) {
		case eTrackPress:
			Highlight(On);
			state= cIdNone;
			if (!gInButtonFlush && menu && Enabled()) {
				state= menu->Popup(contentRect.SW(), this, cIdNone,
					FALSE, TRUE,
					Rectangle(Point(0, -contentRect.extent.y), contentRect.extent));
				Highlight(Off);
			}
			break;
		case eTrackRelease:
			if (state >= 0) {
				EvtHandler *fh= 0;
				Manager *m= GetManager();
				if (m)
					fh= m->GetFirstHandler();
				if (fh)
					fh->PerformCommand(fh->DoMenuCommand(state));
				else
					PerformCommand(DoMenuCommand(state));
				UpdateEvent();
			}
			Highlight(Off);
			break;
		case eTrackExit:
			Highlight(Off);
			break;
		default:
			break;
		}
	}
}

void PullDownButton::DrawHighlight(Rectangle r)
{
	VObject::DrawHighlight(r);
}

//---- MenuItem ----------------------------------------------------------------

NewMetaImpl(MenuItem,MenuButton, (T(lastxpos), T(enterxpos)));

MenuItem::MenuItem(int id, VObject *v, Menu *m) : MenuButton(id, m)
{
	Add(v);
}

Metric MenuItem::GetMinSize()
{
	return gLook->MenuItemLayout()->GetMinSize(this);
}

void MenuItem::DrawInner(Rectangle, bool highlight)
{
	int code= 0;
	SETBIT(code, 4);
	if (highlight)
		SETBIT(code, 3);
	if (Enabled())
		SETBIT(code, 5);
	gLook->MenuItemLayout()->Adorn(this, contentRect, code);
}

void MenuItem::SetOrigin(Point at)
{
	VObject::SetOrigin(at);
	gLook->MenuItemLayout()->SetOrigin(this, at);
}

void MenuItem::DoTrackMouse(TrackPhase atp, Point p)
{
	if (Enabled() && menu) {
		switch (atp) {
		case eTrackPress:
			Highlight(On);
			enterxpos= lastxpos= p.x;
			state= -1;
			break;
		case eTrackMove:
		case eTrackIdle:
			if (p.x > lastxpos &&
					(p.x > enterxpos+cPullRight || p.x > At(0)->contentRect.E().x)) {
				p.y= contentRect.W().y-2;
				state= menu->Pulldown(p, this);
				lastxpos= contentRect.SE().x+1;
			} else
				lastxpos= p.x;
			break;
		case eTrackRelease:
		case eTrackExit:
			if (state != cIdNone)
				Control(state, cPartToggle, (void*)0);
			Highlight(Off);
		default:
			lastxpos= contentRect.SE().x+1;
			enterxpos= p.x;
			break;
		}
	}
}

